<template>
    <div>
        <div ref="point" :class="classes" :style="styles">
            <slot></slot>
        </div>
        <div v-show="slot" :style="slotStyle"></div>
    </div>
</template>

<script>
import { prefixCls } from '../prefix'
import './affix.css'

function getScroll(target, top) {
    const prop = top ? 'pageYOffset' : 'pageXOffset';
    const method = top ? 'scrollTop' : 'scrollLeft';

    let ret = target[prop];

    if (typeof ret !== 'number') {
        ret = window.document.documentElement[method];
    }

    return ret;
}

function getOffset(element) {
    const rect = element.getBoundingClientRect();

    const scrollTop = getScroll(window, true);
    const scrollLeft = getScroll(window);

    const docEl = window.document.body;
    const clientTop = docEl.clientTop || 0;
    const clientLeft = docEl.clientLeft || 0;

    return {
        top: rect.top + scrollTop - clientTop,
        left: rect.left + scrollLeft - clientLeft
    };
}


export default {
    name: `${prefixCls}Affix`,
    props: {
        offsetTop: {//固定距离顶部距离
            type: Number,
            default: 0
        },
        offsetBottom: Number
    },
    data() {
        return {
            prefixCls: prefixCls,
            affix: false,
            styles: {},
            slot: false,
            slotStyle: {}
        }
    },
    computed: {
        offsetType() {
            let type = 'top';
            if (this.offsetBottom >= 0) {
                type = 'bottom';
            }

            return type;
        },
        classes() {
            return [
                {
                    [`${prefixCls}-affix`]: this.affix
                }
            ];
        }
    },
    mounted() {
        window.addEventListener('scroll', this.handleScroll, false);
        window.addEventListener('resize', this.handleScroll, false);
        this.$nextTick(()=>{
            this.handleScroll();
        })
    },
    beforeDestroy() {
        window.removeEventListener('scroll', this.handleScroll, false);
        window.removeEventListener('resize', this.handleScroll, false);
    },
    methods: {
        handleScroll() {
            const affix = this.affix;
            const scrollTop = getScroll(window, true);
            const elOffset = getOffset(this.$el);
            const windowHeight = window.innerHeight;
            const elHeight = this.$el.getElementsByTagName('div')[0].offsetHeight;

            // 固定顶部
            if ((elOffset.top - this.offsetTop) < scrollTop && this.offsetType == 'top' && !affix) {
                this.affix = true;
                this.slotStyle = {
                    width: this.$refs.point.clientWidth + 'px',
                    height: this.$refs.point.clientHeight + 'px'
                };
                this.slot = true;
                this.styles = {
                    top: `${this.offsetTop}px`,
                    left: `${elOffset.left}px`,
                    width: `${this.$el.offsetWidth}px`
                };

                this.$emit('on-change', true);
            } else if ((elOffset.top - this.offsetTop) > scrollTop && this.offsetType == 'top' && affix) {
                this.slot = false;
                this.slotStyle = {};
                this.affix = false;
                this.styles = null;

                this.$emit('on-change', false);
            }

            // 固定底部
            if ((elOffset.top + this.offsetBottom + elHeight) > (scrollTop + windowHeight) && this.offsetType == 'bottom' && !affix) {
                this.affix = true;
                this.styles = {
                    bottom: `${this.offsetBottom}px`,
                    left: `${elOffset.left}px`,
                    width: `${this.$el.offsetWidth}px`
                };

                this.$emit('on-change', true);
            } else if ((elOffset.top + this.offsetBottom + elHeight) < (scrollTop + windowHeight) && this.offsetType == 'bottom' && affix) {
                this.affix = false;
                this.styles = null;

                this.$emit('on-change', false);
            }
        }
    }
}
</script>